// g++ -std=c++11 -o tcp_echo_server -lgod tcp_echo_server.cpp

#include <iostream>

#include "god/config.h"
#include "god/def.h"
#include "god/io_scheduler.h"
#include "god/log.h"
#include "god/net/socket.h"
#include "god/type.h"

using namespace god;
using namespace god::net;

static logger::ptr g_logger = log::lookup("tcp_echo_server");

static config_var<std::string>::ptr g_listen_ifname =
    config::lookup<std::string>("ifname", "*", "Listen interface name");

static const ip_address::port_type g_port = 2222;
static const socket::size_type g_block_size = 10240;

std::ostream & operator<<(std::ostream &os, const address::ptr &val) {
    if (val) {
        return os << *val;
    } else {
        return os << "nullptr";
    }
}

void handle_read(socket::ptr s) {
    GOD_LOG_INFO(g_logger) << "处理连接: [" << s->local_address() << ", " <<
        s->remote_address() << "]";
    try {
        buffer buf;
        while (true) {
            socket::size_type bytes = s->receive(buf, g_block_size);
            if (bytes == 0) {
                break;
            }
            GOD_LOG_INFO(g_logger) << "收到 " << bytes << "字节数据";
            s->send(buf, 0, bytes);
            buf.consume(bytes);
        }
    } catch (...) {
        GOD_LOG_ERROR(g_logger) << boost::current_exception_diagnostic_information();
    }
    GOD_LOG_INFO(g_logger) << "断开连接: [" << s->local_address() << ", " <<
        s->remote_address() << "]";
    s->shutdown();
}

void handle_accept(io_scheduler *scheduler, socket::ptr s) {
    try {
        GOD_LOG_INFO(g_logger) << "监听 " << s->local_address();
        while (true) {
            socket::ptr client = s->accept();
            GOD_LOG_INFO(g_logger) << "收到新连接: [" << client->local_address() << ", " <<
                client->remote_address() << "]";
            scheduler->schedule(std::bind(&handle_read, client));
        }
    } catch (...) {
        GOD_LOG_ERROR(g_logger) << boost::current_exception_diagnostic_information();
    }
}

int main(int argc, char *argv[]) {
    io_scheduler scheduler;
    try {
        config::load_from_command_line(argc, argv);
        address::addresses addrs;
        address::interface_addresses(addrs, g_listen_ifname->val(), address_family::inet);
        if (addrs.empty()) {
            GOD_LOG_INFO(g_logger) << "无效的网卡名字: " << g_listen_ifname->val();
            return 1;
        }
        for (address::addresses::const_iterator it = addrs.begin(); it != addrs.end(); ++it) {
            address::ptr addr = *it;
            std::static_pointer_cast<ip_address>(addr)->set_port(g_port);
            socket::ptr s = addr->create_socket(&scheduler, socket_type::stream);
            socket::reuse_address_option opt(true);
            s->set_option(opt);
            s->bind(addr);
            s->listen();
            scheduler.schedule(std::bind(&handle_accept, &scheduler, s));
        }
    } catch (...) {
        GOD_LOG_ERROR(g_logger) << boost::current_exception_diagnostic_information();
    }
    scheduler.dispatch();
    return 0;
}
